home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Applications / Communication / NewsBase / Source / SideSplitView.m < prev    next >
Text File  |  1993-01-12  |  7KB  |  247 lines

  1. /* 
  2.  * SideSplitView.m
  3.  *
  4.  * Purpose:
  5.  *        This object implements a split view which divides a view into two
  6.  *        side by side areas. These areas are intended to be filled by subviews.
  7.  *        The user can then change the porportion of the subviews to one
  8.  *        another. The purpose is to provide developers with an alternative to
  9.  *        NXSplitView.
  10.  *
  11.  * You may freely copy, distribute, and reuse the code in this example.
  12.  * NeXT disclaims any warranty of any kind, expressed or  implied, as to its
  13.  * fitness for any particular use.
  14.  *
  15.  * Written by: Mary McNabb
  16.  * Created: Apr 91
  17.  *
  18.  */
  19.  
  20. #import "SideSplitView.h"
  21. #import <appkit/NXImage.h>
  22. #import <dpsclient/psops.h>
  23. #import <dpsclient/wraps.h>
  24. #import <appkit/Application.h>
  25. #import <math.h>
  26. #import <libc.h>
  27.  
  28. #define eventMask NX_MOUSEUPMASK | NX_MOUSEDRAGGEDMASK
  29.  
  30. #define DIVIDERWIDTH 8.0        /* the divider is 8 pixels wide. */
  31. #define HALFWIDTH 4.0
  32.  
  33. static NXRect   dimpleRect = {{3.0, 5.0}, {8.0, 7.0}};
  34.  
  35. /* Retrace is 1/67 of sec * 10^6 micro secs per second */
  36. #define RETRACE    (1000000.0/67.0)  /* vertical retrace period in micro secs */
  37.  
  38. @implementation SideSplitView
  39.  
  40. /*
  41.  * initialize the split view. also initialize the size of the divider
  42.  */
  43. - initFrame:(NXRect *) theRect
  44. {
  45.     NXSize    dimpleSize;
  46.     
  47.     srandom(time(0));        /* initialize random number generator */
  48.     [super initFrame:theRect];
  49.     [self setAutoresizeSubviews:YES];
  50.     dimple = [NXImage findImageNamed:"Dimple"];
  51.     [dimple getSize:&dimpleSize];
  52.     
  53.     dimpleHalfHeight = floor(dimpleSize.height / 2.0);
  54.  
  55.     dividerRect.origin.x = 0.0;
  56.     dividerRect.origin.y = bounds.origin.y;
  57.     dividerRect.size.height = bounds.size.height;
  58.     dividerRect.size.width = dimpleSize.width + 3.0;
  59.     
  60.     minX = 0.0;
  61.  
  62.     return self;
  63. }
  64.  
  65. /*
  66.  * initialize the subviews of the split view.
  67.  */
  68. - initViews    
  69. {
  70.     [window disableFlushWindow];
  71.     [self adjustSubviews];            /* just in case we were sloppy in IB */
  72.     [window reenableFlushWindow];
  73.     [window flushWindow];
  74.     [self display];
  75.     return self;
  76. }
  77.  
  78. /*
  79.  * take advantage of IB. Use these set methods to initialize the subviews
  80.  */
  81. - setLeftView:(id)newView
  82. {
  83.     NXRect leftViewFrame;
  84.     
  85.     leftView = newView;
  86.     [leftView setAutosizing:NX_WIDTHSIZABLE|
  87.         NX_HEIGHTSIZABLE|NX_MAXXMARGINSIZABLE];
  88.             
  89.     [leftView getFrame:&leftViewFrame];
  90.     dividerRect.origin.x = leftViewFrame.size.width;
  91.     
  92.     [self addSubview:leftView];
  93.     return self;
  94. }
  95.  
  96. /*
  97.  * don't bother with the size and origin of the view as it gets completely reset in
  98.  * adjustSubviews
  99.  */
  100. - setRightView:(id)newView
  101. {
  102.     rightView = newView;
  103.     
  104.     [rightView setAutosizing:NX_WIDTHSIZABLE|
  105.         NX_HEIGHTSIZABLE|NX_MINXMARGINSIZABLE];
  106.     [self addSubview:rightView];
  107.     return self;
  108. }
  109.  
  110. - (BOOL)acceptsFirstMouse
  111. {
  112.     return YES;
  113. }
  114.  
  115. /*
  116.  * The side split view consists of a light gray background, and a dimple.
  117.  * Relies on the subviews to draw bevels, etc.
  118.  */
  119. - drawSelf:(const NXRect *)r :(int)c
  120. {
  121.     NXPoint dimplePoint;
  122.  
  123.     PSsetgray(NX_LTGRAY);
  124.     NXRectFill(&bounds);
  125.  
  126.     dimplePoint.x = dividerRect.origin.x + 1.0;
  127.     dimplePoint.y = floor(dividerRect.origin.y +
  128.                   dividerRect.size.height / 2.0 - dimpleHalfHeight);
  129.  
  130.     [dimple composite:NX_SOVER toPoint:&dimplePoint];
  131.  
  132.     return self;
  133. }
  134.  
  135. /*
  136.  * Controls the movement of the divider as the user slides it with the mouse
  137.  */
  138. - mouseDown:(NXEvent *) theEvent
  139. {
  140.     NXPoint localPoint = theEvent->location;
  141.     NXEvent *nextEvent;
  142.     NXCoord lastX=0.0;
  143.     int oldMask;
  144.  
  145.     [self convertPoint:&localPoint fromView:nil];
  146.     if (!NXMouseInRect(&localPoint, ÷rRect, NO))
  147.         return self;
  148.     oldMask = [window addToEventMask:NX_MOUSEDRAGGEDMASK];
  149.  
  150.         /* We've gotten a mouse down on the divider, so go ahead and draw the slider now */
  151.     [self lockFocus];
  152.     PSsetinstance(YES);
  153.     PSsetgray(.50);
  154.     PSsetalpha(0.3333);
  155.     PScompositerect(localPoint.x-HALFWIDTH, dividerRect.origin.y,
  156.         DIVIDERWIDTH, dividerRect.size.height, NX_COPY);
  157.     
  158.         /* while the user is dragging composite a new slider in new postion -- watching for
  159.          * boundary conditions. Exit loop on mouse up.
  160.          */
  161.      do {
  162.         nextEvent = [NXApp getNextEvent:eventMask];
  163.         localPoint = nextEvent->location;
  164.         [self convertPoint:&localPoint fromView:nil];
  165.         if (localPoint.x < minX) localPoint.x = minX;
  166.         if (localPoint.x > maxX) localPoint.x = maxX;
  167.         if (localPoint.x != lastX) {
  168.             /* wait some random amount of time within retrace period. */
  169.             usleep((random() % (int)RETRACE));
  170.             PSnewinstance();
  171.             PScompositerect(localPoint.x-HALFWIDTH, dividerRect.origin.y,
  172.                 DIVIDERWIDTH, dividerRect.size.height, NX_COPY);
  173.             lastX = localPoint.x;
  174.         }
  175.     } while (nextEvent->type != NX_MOUSEUP);
  176.  
  177.         /* User is done dragging. Move the divider to new location
  178.          */    
  179.     dividerRect.origin.x = localPoint.x - HALFWIDTH;
  180.     PSsetinstance(NO);
  181.     [self unlockFocus];
  182.     [self adjustSubviews];
  183.     [self display];
  184.     [window setEventMask:oldMask];
  185.     
  186.     return self;
  187. }
  188.  
  189. /*
  190.  * blits the dimple to the screen in the right spot
  191.  */
  192. - drawDimple
  193. {
  194.     NXPoint origin;
  195.     origin.x = dividerRect.origin.x;
  196.     origin.y = floor(dividerRect.origin.y + dividerRect.size.height/2.0 - dimpleRect.size.height/2.0);
  197.     [dimple composite:NX_COPY fromRect:&dimpleRect toPoint:&origin];
  198.     return self;
  199. }
  200.  
  201. /*
  202.  * modifies the size of the subviews after user has positioned the divider, or
  203.  * has resized the window.
  204.  * also used to initialize the sizes of the subviews.
  205.  */
  206. - adjustSubviews
  207. {
  208.     NXRect leftViewFrame, rightViewFrame;
  209.  
  210.         /* first the left one  */
  211.     [leftView getFrame:&leftViewFrame];
  212.     leftViewFrame.size.width = dividerRect.origin.x - leftViewFrame.origin.x;
  213.     leftViewFrame.size.height = bounds.size.height;
  214.     leftViewFrame.origin.x = bounds.origin.x;
  215.     leftViewFrame.origin.y = bounds.origin.y;
  216.     [leftView setFrame:&leftViewFrame];
  217.     [window invalidateCursorRectsForView:leftView];
  218.  
  219.         /* then the right one */
  220.     [rightView getFrame:&rightViewFrame];
  221.     rightViewFrame.origin.x = leftViewFrame.size.width + DIVIDERWIDTH;
  222.     rightViewFrame.origin.y = bounds.origin.y;
  223.     rightViewFrame.size.width = bounds.size.width - rightViewFrame.origin.x;
  224.     rightViewFrame.size.height = bounds.size.height;
  225.     [rightView setFrame:&rightViewFrame];
  226.     [window invalidateCursorRectsForView:rightView];
  227.     
  228.         /* update dividerRect in case of resize of window */
  229.     dividerRect.origin.x = leftViewFrame.size.width;
  230.     dividerRect.size.height = leftViewFrame.size.height;
  231.     dividerRect.origin.y = leftViewFrame.origin.y;
  232.     maxX = bounds.size.width - HALFWIDTH;
  233.     return self;
  234. }
  235.  
  236. /*
  237.  * called when the window gets resized
  238.  */
  239. - resizeSubviews:(const NXSize *)oldSize 
  240. {
  241.     [super resizeSubviews:oldSize];
  242.     [self adjustSubviews];
  243.     return self;
  244. }
  245.  
  246. @end
  247.